package asf.forms
{
	import asf.interfaces.IComboBox;
	import asf.interfaces.IFormField;
	import asf.interfaces.IInputField;
	import asf.interfaces.IList;
	import asf.interfaces.IListBox;
	
	import com.adobe.utils.StringUtil;
	
	import flash.display.DisplayObject;
	import flash.utils.getDefinitionByName;
	
	public class FormField
	{
		private var raw:XML;
		private var _view:IFormField;
		
		public function FormField( p_raw:XML = null, p_view:IFormField = null )
		{
			if( p_view )
			{
				this._view = p_view;
			}
			
			if( p_raw )
			{
				this.raw = p_raw;
				
				if( _view == null )
				{
					if( type == FieldType.RADIO_GROUP )
					{
						_view = new RadioGroup( XML( raw.items ) );
					}
					else
					{
						_view = new baseClass( ) as IFormField;
					}
				}
				
				applyProperties( );
				applyPropsByType( );
			}
		}
		
		public function getRawXML( ):XML
		{
			return this.raw.copy( );
		}
		
		private function applyProperties( ):void
		{
			var props:Array = [ "x", "y", "alpha", "rotation", "width", "height" ];
			var prop:String;
			
			for each( prop in props ) apply( prop );
		}
		
		private function applyPropsByType( ):void
		{
			switch( type )
			{
				case FieldType.TEXT_AREA:
				case FieldType.INPUT:
				{
					if( gav( "maxChars" ) )
					{
						( _view as IInputField ).setMaxChars( gav( "maxChars" ) );
					}
					
					if( gav( "restrict" ) )
					{
						( _view as IInputField ).setRestrict( gav( "restrict" ) );
					}
					
					if( gav( "password" ) )
					{
						( _view as IInputField ).setPassword( gav( "password" ) == "true" );
					}
					
					if( gav( "value" ) )
					{
						view.setValue( gav( "value" ) );
					}
					
					break;
				}
				case FieldType.LIST_BOX:
				{
					( _view as IListBox ).setMultiple( gav( "multiple" ) == "true" );
					fillListField( _view as IList );
					
					if( gav( "selectedIndexes" ) )
					{
						( view as IListBox ).setSelectedIndexes( String( gav( "selectedIndexes" ) ).split( "," ) );
					}
					
					break;
				}
				case FieldType.COMBO_BOX:
				{
					if( gav( "maxVisible" ) )
					{
						( _view as IComboBox ).setMaxVisible( gav( "maxVisible" ) );
					}
					
					fillListField( _view as IList );
					
					break;
				}
				case FieldType.RADIO_GROUP:
				{
					break;
				}
			}
		}
		
		public function getValue( ):*
		{
			return _view.getValue( );
		}
		
		private function fillListField( field:IList ):void
		{
			var item:XML;
			
			for each( item in raw.items.item )
			{
				field.addItem( item.@label, item.@value || item.value );
			}
			
			if( gav( "selectedIndex" ) )
			{
				field.setSelectedIndex( int( gav( "selectedIndex" ) ) );
			}
		}
		
		//get attribute value
		private function gav( name:String ):*
		{
			var attr:String = StringUtil.trim( String( raw.attribute( name ) ) );
			var node:String = StringUtil.trim( String( raw[ name ] ) );
			
			if( attr != "" )
				return attr;
			else if( node != "" ) 
				return node;
			
			return null; 
		}
		
		private function apply( prop:String ):void
		{
			var value:* = gav( prop );
			
			switch( prop )
			{
				case "height": 
				{
					if( value != null ) view.setHeight( value );
					
					break;
				}
				case "width":
				{
					if( value != null ) view.setWidth( value );
					
					break;
				}
			}
			
			if( value != null ) view[ prop ] = value;
		}
		
		public function focus( ):void
		{
			this.view.focus( );
		}
		
		public function blur( ):void
		{
			this.view.blur( );
		}
		
		public function enable( ):void
		{
			this.view.enable( );
		}
		
		public function disable( ):void
		{
			this.view.disable( );
		}
		
		public function clearValue( ):void
		{
			this.view.clearValue( );
		}
		
		public function set requiredMessage( value:String ):void
		{
			raw.@requiredMessage = value;
		}
		
		public function set invalidMessage( value:String ):void
		{
			raw.@invalidMessage = value;
		}
		
		public function set mismatchMessage( value:String ):void
		{
			raw.@mismatchMessage = value;
		}
		
		public function get requiredMessage( ):String
		{
			return raw.@requiredMessage || raw.requiredMessage;
		}
		
		public function get mismatchMessage( ):String
		{
			return raw.@mismatchMessage || raw.mismatchMessage;
		}
		
		public function get required( ):Boolean
		{
			return ( raw.@required || raw.required ) == "true";
		}
		
		public function get invalidMessage( ):String
		{
			return raw.@invalidMessage || raw.invalidMessage;
		}
		
		public function get id( ):String
		{
			return raw.@id || raw.id;
		}
		
		public function get regExp( ):RegExp
		{
			var str:String = String( raw.@regExp || raw.regExp );
			var flags:String = String( raw.@regExpFlags || raw.regExpFlags );
			
			if( str != "" )
			{
				return new RegExp( str, flags );
			}
			
			return null;
		}
		
		public function isValidRegExp( ):Boolean
		{
			if( regExp == null ) return true;
			return regExp.test( String( this.view.getValue( ) ) );
		}
		
		public function get baseClassName( ):String
		{
			return raw.@baseClass || raw.baseClass;
		}
		
		public function get baseClass( ):Class
		{
			return getDefinitionByName( baseClassName ) as Class;
		}
		
		public function get type( ):String
		{
			return raw.@type || raw.type;
		}
		
		public function get view( ):IFormField
		{
			return _view;
		}
		
		public function get matchID( ):String
		{
			return StringUtil.trim( String( raw.@match || raw.match ) );
		}
		
		public function set x( value:Number ):void
		{
			( view as DisplayObject ).x = value;
		}
		
		public function get x( ):Number
		{
			return ( view as DisplayObject ).x;
		}
		
		public function set y( value:Number ):void
		{
			( view as DisplayObject ).y = value;
		}
		
		public function get y( ):Number
		{
			return ( view as DisplayObject ).y;
		}
		
		public function set alpha( value:Number ):void
		{
			( view as DisplayObject ).alpha = value;
		}
		
		public function get alpha( ):Number
		{
			return ( view as DisplayObject ).alpha;
		}
		
		public function dispose( ):void
		{
			_view.dispose( );
			_view = null;
			raw = null;
		}
	}
}